package com.socodethis.spaceex;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

import com.socodethis.spaceex.math.cPoint;

public class SolvableClass {
	cPoint entrance, dimensions, exit;
	ArrayList<buttonClass> buttons = new ArrayList<buttonClass>();
	ArrayList<cPoint> doors = new ArrayList<cPoint>();
	int[][] map, backupMap;
	public SolvableClass(int[][] map, cPoint dimensions, cPoint entrance){
		this.dimensions = new cPoint(dimensions);
		this.entrance = new cPoint(entrance);
		this.exit = new cPoint(this.entrance);
		this.map = new int[(int) dimensions.getX()][(int) dimensions.getY()];
		this.backupMap = new int[(int) dimensions.getX()][(int) dimensions.getY()];
		for(int y = 0; y < dimensions.getY();y++){
			for(int x = 0; x < dimensions.getX();x++){
				this.map[x][y] = map[x][y];
				this.backupMap[x][y] = map[x][y];
				if(map[x][y]==2){
					doors.add(new cPoint(x,y));
					this.map[x][y] = 0;
				}
			}
		}
		//exit.printPoint();
		generateButtonLocations();
	}
	//This should hopefully never be reached
	//Draws a floor map with the impossible dungeon so that 
	//changes can be made
	public void reOrderTryAgain(){
		doors.clear();
		for(int y = 0; y < dimensions.getY();y++){
			for(int x = 0; x < dimensions.getX();x++){
				this.map[x][y] = backupMap[x][y];
				if(map[x][y]==2){
					doors.add(new cPoint(x,y));
					this.map[x][y] = 0;
				}
			}
		}
		printFloorMap();
		//System.out.println("New Matrix Made: " + dimensions.getX() +":"+dimensions.getY() + " Size: " + doors.size());
		Collections.shuffle(doors);
	}
	public void generateButtonLocations(){ 
		shortestPath pathFinder;
		int position = 0;
		boolean found = false;
		cPoint foundDoor = new cPoint(0,0);
		int lastSize = doors.size();
		int lastSizeCount = 0;
		//System.out.println("Dimensions");
		//dimensions.printPoint();
		//System.out.println("Doors: "+doors.size());
		
		while(!doors.isEmpty()){
			//System.out.println("DungDim: " + dimensions.getX() +":"+dimensions.getY() + " Size: " + doors.size());
			for(int i = 0; i < doors.size();i++){
				//changes the door to a floor
				map[(int) doors.get(i).getX()][(int) doors.get(i).getY()] = 1;
				//see if the player can get there
				pathFinder = new shortestPath(map,entrance, doors.get(i),(int)dimensions.getX(),(int)dimensions.getY());
				//If the player can get there, store the location of the door
				if(pathFinder.returnPath().size()>=2){
					foundDoor = new cPoint(doors.get(i));
					position = i;
					found = true;
				}
				map[(int) doors.get(i).getX()][(int) doors.get(i).getY()] = 0;
			}
			if(!found && lastSize == doors.size()){
				lastSizeCount++;
			}
			//If you found something, put the button in a random place that is accessible to the player
			if(found){
				buttons.add(new buttonClass(false,foundDoor,getAccessible()));
				if(doors.size() == 1){
					exit = new cPoint(getNotAccessible());
				}
				map[(int) foundDoor.getX()][(int) foundDoor.getY()] = 1;
				doors.remove(position);
				lastSizeCount = 0;
				found = false;
			}
			if(lastSizeCount == 2){
				//System.out.println("Infinite Loop Encountered. Resetting Matrix");
				reOrderTryAgain();
			}
			lastSize = doors.size();
		}
		//System.out.println("Matrix Finished: " + doors.size());
	}
	//Get an empty spot that is accessible to the player without having to open doors
	public cPoint getAccessible(){
		shortestPath pathFinder;
		cPoint pickedPoint =  new cPoint(0,0);
		ArrayList <cPoint> mapList = new ArrayList<cPoint>();
		int x,y;
		for(int Y = 0; Y<dimensions.getY(); Y++){
			for (int X=0; X<dimensions.getX(); X++){
				if (backupMap[X][Y] == 1){
					mapList.add(new cPoint(X,Y));
				}
			}
		}
		Collections.shuffle(mapList);
		for(cPoint randomPoint : mapList){
			pathFinder = new shortestPath(this.map,entrance, randomPoint,(int)dimensions.getX(),(int)dimensions.getY());
			if (!(pathFinder.returnPath().size()<2) && !randomPoint.cEquals(entrance) && !containsButton(randomPoint)){
				pickedPoint = new cPoint(randomPoint);
				break;
			}
		}
		return pickedPoint;
	}
	
	//This is to determine the correct place to put the exit. Not random due to the probable odds of picking a square that works
	public cPoint getNotAccessible(){
		
		shortestPath pathFinder;
		cPoint pickedPoint =  new cPoint(0,0);
		ArrayList <cPoint> mapList = new ArrayList<cPoint>();
		int x,y;
		for(int Y = 0; Y<dimensions.getY(); Y++){
			for (int X=0; X<dimensions.getX(); X++){
				if (backupMap[X][Y] == 1){
					mapList.add(new cPoint(X,Y));
				}
			}
		}
		
		Collections.shuffle(mapList);
		for(cPoint randomPoint : mapList){
			pathFinder = new shortestPath(this.map,entrance, randomPoint,(int)dimensions.getX(),(int)dimensions.getY());
			if ((pathFinder.returnPath().size()<2) && !randomPoint.cEquals(entrance) && !containsButton(randomPoint) ){
				pickedPoint = new cPoint(randomPoint);
				break;
			}
		}
		return pickedPoint;
	}
	
	public int getButtonSize(){
		return buttons.size();
	}
	public buttonClass getButtonIndex(int i){
		return buttons.get(i);
	}
	public cPoint getExit(){
		return exit;
	}
	public void printFloorMap(){
		for(int y = 0; y < dimensions.getY();y++){
			for(int x = 0; x < dimensions.getX();x++){
				System.out.print(backupMap[x][y]);
			}
			System.out.println();
		}
	}
	public boolean containsButton(cPoint point){
		for(buttonClass button:buttons){
			if(button.getButtonLocation().cEquals(point)){
				return true;
			}
		}
		return false;
	}
}
